home *** CD-ROM | disk | FTP | other *** search
- TITLE KEYBOARD BUFFER
- PAGE 60, 132
-
- ;**********************************************************************
- ;* Keyboard Buffer and Editor VERSION 2.0
- ;*
- ;* This program provides two independent functions:
- ;* 1) it extends the DOS_keyboard_buffer to 128 characters and
- ;* 2) it provides command-line storage and editing facilities
- ;*
- ;* Source: self contained 8088/8086 Macro Assembler Language
- ;* Script: MASM KBEDIT;
- ;* LINK KBEDIT;
- ;* EXE2BIN KBEDIT.EXE KBEDIT.SYS
- ;*
- ;* Usage: install as a device driver by including a statement
- ;* in the CONFIG.SYS file of the form:
- ;*
- ;* DEVICE=KBEDIT.SYS [B:nnn] [C:nnn] [K:nnn] [/A] [/N]
- ;*
- ;* B:nnn is buffer size for stored strings in bytes
- ;* (default = 512)
- ;* C:nnn is maximum number of strings in the string buffer
- ;* (default = 32)
- ;* K:nnn is keyboard buffer size in characters
- ;* (default = 128)
- ;*
- ;**********************************************************************
-
- JMPS MACRO LABEL
- JMP SHORT LABEL
- ENDM
-
- CLR MACRO REG
- SUB REG, REG
- ENDM
-
- GET_CHAR MACRO
-
- ;----- return keyboard input in AL through DOS-call
- ;
-
- MOV AH, 8 ;; function number
- INT 21H
- ENDM
-
-
- ; -----DOS-keyboard pointers
- ;
-
- DOS_DATA_AREA SEGMENT AT 40H
-
- ORG 17H
- DOS_KB_FLAG DB ?
- ORG 1AH
- KB_HEAD DW ?
- KB_TAIL DW ?
- ORG 71H
- DOS_BREAK_FLAG DW ?
- ORG 80H
- DOS_BUFFER_START DW ?
- DOS_BUFFER_END DW ?
-
- DOS_DATA_AREA ENDS
-
-
- ;----- interrupt_vector_adresses_equates
- ;
-
- KB_INTERRUPT EQU 4*9H
- KB_IO_ROUTINE EQU 4*16H
- DOS_FUNCTION_INT EQU 4*21H
-
- ;----- equates
- ;
-
- NULL EQU 00H
- CR EQU 0DH
- LF EQU 0AH
- BACKSPACE EQU 08H
- ESCAPE EQU 1BH
- CTRL_U EQU 15H
- CTRL_W EQU 17H
- EOF EQU 1AH
- ACK EQU 06H
- TAB EQU 09H
-
- OFF EQU 0
- ON EQU NOT OFF
- NOT_INST EQU 0AAH ;
-
-
- ;-----
- ; the following keys are identified by extended ascii-codes
- ; the second byte is given in these equates
- ;
-
- INSERT EQU 052H
- DELETE EQU 053H
- CURSOR_LEFT EQU 04BH
- CURSOR_RIGHT EQU 04DH
- PREV_LINE EQU 048H ; = cursor up
- NEXT_LINE EQU 050H ; = cursor down
- CURSOR_BEGIN EQU 047H ; = home key
- CURSOR_END EQU 04FH ; = end key
- F1 EQU 03BH
- F2 EQU 03CH
- F3 EQU 03DH
- F4 EQU 03EH
- F5 EQU 03FH
- F6 EQU 040H
- F7 EQU 041H
- CTRL_LEFT EQU 073H
- CTRL_RIGHT EQU 074H
- CTRL_HOME EQU 077H
- CTRL_END EQU 075H
- CTRL_PGUP EQU 084H
- CTRL_PGDN EQU 076H
- SHIFT_F5 EQU 058H
- SHIFT_F6 EQU 059H
- ALT_1 EQU 078H
- ALT_2 EQU 079H
- ALT_3 EQU 07AH
- ALT_4 EQU 07BH
- ALT_5 EQU 07CH
- ALT_6 EQU 07DH
- ALT_7 EQU 07EH
- ALT_8 EQU 07FH
- ALT_9 EQU 080H
- ALT_0 EQU 081H
-
-
-
-
- CODE SEGMENT PUBLIC
- ASSUME CS:CODE
-
- START_CODE = $
-
- HEADER DD -1 ; device_driver obligatory
- ; first four bytes
- ATTRIBUTE DW 8000H ; attribute byte:
-
- DW D_STRATEGY
- DW D_INTERRUPT
-
- DRVNAME DB 'KBEDT '
-
- ;----- installation messages
- ;
-
- MSG_VERSION DB 'Keyboard Buffer and Command Line Editor,'
- DB ' Version 2.0', CR, LF, LF, NULL
- DB ' author: P. Kranenburg'
- DB ' University of Leiden, The Netherlands'
-
-
- ;----- keyboard related messages
- ;
-
- MSG_KB_1 DB ' Keyboard buffer size : ', NULL
- MSG_KB_2 DB ' characters', CR, LF, NULL
-
- MSG_KB_NO_1 DB ' KeyBoard Buffer size ', NULL
- MSG_KB_NO_2 DB ' is too small: not installed', CR, LF, NULL
- MSG_KB_IN DB ' KeyBoard Buffer Installed'
- DB CR, LF, NULL
- MSG_KB_UN DB ' KeyBoard Buffer Uninstalled'
- DB CR, LF, NULL
- MSG_KB_PR DB ' Keyboard Buffer already installed'
- DB CR, LF, NULL
- MSG_KB_NOT_PR DB ' Keyboard Buffer was not active'
- DB CR, LF, NULL
-
-
- ;----- editor related messages
- ;
-
- MSG_EDT_1 DB ' Command line buffer size : ', NULL
- MSG_EDT_2 DB ' bytes', CR, LF
- DB ' Number of commands in buffer : ', NULL
- MSG_EDT_3 DB ' ', CR, LF, LF, NULL
-
- MSG_EDT_IN DB ' Command Line Editor Installed'
- DB CR, LF, NULL
-
- MSG_EDT_UN DB ' Command Line Editor Uninstalled'
- DB CR, LF, NULL
-
- MSG_EDT_PR DB ' Command Line Editor already installed'
- DB CR, LF, NULL
-
- MSG_EDT_NOT_PR DB ' Command Line Editor was not active'
- DB CR, LF, NULL
-
-
- ;----- pointers to request_header
- ;
-
- REQ_HEADER_OFS DW ?
- REQ_HEADER_SEG DW ?
-
-
- ;----- control data sent to output-routine of driver
- ;
-
- EXPECTSECOND DB OFF ; first/second byte indicator
- FIRSTPART DB LOW ON ; first byte of incoming control codes
- KB_INST DB OFF ; keyboard buffer presence flag
- EDT_INST DB NOT_INST; keyboard editor presence flag
- BIOS_TTY_SW DB LOW ON ; true on driver initialization
- TEN DW 10 ; operand for MULtiply operation
-
-
- ;----- local stack for processing buffered input function call
- ;
-
- LOCAL_STACK DW 256 DUP(?)
-
-
- ;----- containers for user stack-segment and -pointer
- ;
-
- CALLERS_STACK_SEGMENT DW ?
- CALLERS_STACK_POINTER DW ?
-
- RET_FROM_STACK_ROUTINES DW ? ; temp var for SETSTACK and RESETSTACK
-
-
- ;----- routines to switch stacks
- ;
-
- SETSTACK PROC NEAR
-
- POP RET_FROM_STACK_ROUTINES ; save return address
- MOV CALLERS_STACK_SEGMENT, SS ; now save user stack
- MOV CALLERS_STACK_POINTER, SP ;
- PUSH CS
- POP SS ; install new stack
- MOV SP, OFFSET LOCAL_STACK + SIZE LOCAL_STACK
- JMP RET_FROM_STACK_ROUTINES ; return
- SETSTACK ENDP
-
- RESETSTACK PROC NEAR
-
- POP RET_FROM_STACK_ROUTINES
- PUSH CALLERS_STACK_SEGMENT
- POP SS ; restore stack registers
- MOV SP, CALLERS_STACK_POINTER ;
- JMP RET_FROM_STACK_ROUTINES
- RESETSTACK ENDP
-
-
-
- ;----- enlarged keyboard buffer
- ;
-
- KBBUFFER_SIZE DW 256
- KBBUFFER DW ?
-
-
- ;----- containers for old interrupt_vector_adresses
- ;
-
- OLD_KEYB_IO DD ?
- OLD_KEYB_INT DD ?
- OLD_FUNCTION_INT DD ?
- OLD_DOS_BUFFER_START DW ?
- OLD_DOS_BUFFER_END DW ?
-
-
-
-
- ;#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
- ;#
- ;# *** Description of data-structure used in Editor-routines ***
- ;#
- ;# Quantities Assignments
- ;#
- ;#
- ;# - actice/inactive switch - - - EDT_INST
- ;#
- ;# Buffer data:
- ;#
- ;# - current character pointer in buffer - - - register DI
- ;# - current number of characters in buffer - - - register BL
- ;# - current number of characters up to but - - - register BH
- ;# not including the current cursor
- ;# - maximum number of characters in buffer - - - register DL
- ;# exclusive final Carriage Return
- ;# - insert/overwrite mode - - - INSERT_TOGGLE
- ;#
- ;# Display data:
- ;#
- ;# - screen coordinates of start displayed string- - - STR_START_POS
- ;# - screen coordinates of end displayed string - - - STR_END_POS
- ;# - current video page - - - VIDEO_PAGE
- ;# - current cursor position on the screen - - - CURSOR_POS
- ;# - cursor shape - - - CURSOR_TYPE
- ;# - current screen width - - - MAX_COL
- ;# - number of character rows - - - MAX_ROW (fixed:25)
- ;#
- ;# - full/partial editing capability - - - FULL_EDIT
- ;# - defer-mode when redirected input/output - - - DEFER_DSPL
- ;# - cursor positioning through ANSI-escape codes- - - ANSI
- ;#
- ;#
- ;#
- ;# Lay-out of the buffer passed through DS:DX
- ;#
- ;#
- ;# +----------+----------+-------+--/ /--+---------+-------+--/ /--+--------+
- ;# | BufLen | #chars | D(1) | ... |D(#chars)| 'CR' | ... | N+3 |
- ;# | = N | in buf | | | | | | |
- ;# +----------+----------+-------+--/ /--+---------+-------+--/ /--+--------+
- ;#
- ;# at offset 0: length of buffer (exclusive first two bytes and final CR)
- ;# 1: length of actual number of characters in buffer
- ;# (exclusive final CR)
- ;# 2 .. [byte(1)]+1 : data
- ;# [byte(2)]+2 : 'Carriage Return'
- ;#
- ;#
- ;# The buffer can contain a string on input as well. This is checked for at
- ;# entrance ( a carriage return must be present at the byte
- ;# with index: [byte(2)]+2 )
- ;# If present the input string is inserted in the string buffer to make it
- ;# available for editing.
- ;#
- ;#
- ;#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
-
-
-
- INSERT_TOGGLE DB OFF
-
- DEFER_DSPL DB OFF
- FULL_EDIT DB OFF
- CURSOR_TYPE DW ? ; cursor-status on entry
- CURSOR_MASK EQU 00011111B ; mask for set cursor
- INSERT_SHIFT DB 4 ; determines cursor-shape
- ; change in INSERT-mode
- CURSOR_POS LABEL WORD
- CURSOR_COL DB ?
- CURSOR_ROW DB ?
- STR_START_POS LABEL WORD
- STR_START_COL DB ?
- STR_START_ROW DB ?
- STR_END_POS LABEL WORD
- STR_END_COL DB ?
- STR_END_ROW DB ?
-
- MAX_ROW EQU 25
- MAX_COL DB 80 ; assumed default for display-width
- VIDEO_PAGE DB 0
-
- ANSI DB OFF
- ANSI_GET_CURSOR DB ESCAPE, '[6n', NULL
-
-
- DEVICE_PROLOGUE PROC NEAR
-
- ;****************************************************************
- ;* Find out about devices attached to standard input and ouput by
- ;* issuing a IOCTL (044H) function call.
- ;*
- ;* If either STDIN or STDOUT is attached to a file then writing
- ;* characters to STDOUT is deferred until editing is complete.
- ;*
- ;* If STDOUT is NOT the Console Output then direct cursor
- ;* manipulation is disabled, i.e. when a multiple line string,
- ;* the cursor position on the screen does not reflect the current
- ;* position in the string.
- ;*
- ;*
-
- STDIN EQU 0
- STDOUT EQU 1
- ISDEV EQU 0080H
- ISCOT EQU 0002H
-
- PUSH DX
- PUSH BX
-
- ;----- initialize variables
- ;
- MOV DEFER_DSPL, ON
- MOV FULL_EDIT, OFF;
- MOV STR_START_POS, 0
- MOV STR_END_POS, 0
- MOV CURSOR_POS, 0
-
- ;----- check standard input
- ;
-
- MOV BX, STDIN ; BX is handle
- MOV AX, 4400H ; AL = 0: get device information
- INT 21H ; status returned in DX
- TEST DX, ISDEV
- JZ DP_LX ; if bit off then file
- ; else device
-
- ;----- check standard output
- ;
-
- MOV BX, STDOUT ; BX is handle
- MOV AX, 4400H ; AL = 0: get device information
- INT 21H ; status returned in DX
- TEST DX, ISDEV
- JZ DP_LX ; bit not set: file
- MOV DEFER_DSPL, OFF ;
- TEST DX, ISCOT
- JZ DP_LX
-
- CMP ANSI, ON ; ANSI or BIOS cursor handling ?
- JE DP_L1
-
- ;----- get video state
- ;
-
- MOV AH, 0FH
- INT 10H
- MOV MAX_COL, AH
- MOV VIDEO_PAGE, BH
-
- ;----- get cursor position and attributes
- ;
-
- MOV AH, 03 ; BH still contains video page number
- INT 10H ; get current cursor
- MOV CURSOR_TYPE, CX ; save cursor data
- JMPS DP_L2
-
- DP_L1:
- LEA SI, ANSI_GET_CURSOR ; get cursor position through
- CALL PRINT ; ANSI-sequence <esc>[6n
-
- CALL ANSI_REPLY ; get ANSI-reply
-
- DP_L2:
- MOV CURSOR_POS, DX ; initialize cursor variables
- MOV STR_START_POS, DX ;
- MOV STR_END_POS, DX ;
- MOV FULL_EDIT, ON ;
-
- DP_LX:
- POP BX
- POP DX
- RET
- DEVICE_PROLOGUE ENDP
-
-
- DEVICE_EPILOGUE PROC NEAR
-
- ;-----------------------------------------------------
- ; in: SI = pointer to start of string
- ; If DEFER_DSPL is ON then now is the time to display
- ; the completed current string.
- ; A final carriage return is sent to standard output
- ; in all cases.
- ;
-
- MOV INSERT_TOGGLE, OFF
- CALL SET_CURSOR_TYPE
-
- CMP DEFER_DSPL, ON
- MOV DEFER_DSPL, OFF ; tell DISPLAY_COMPLEX to no longer
- ; postpone display
- JNE DE_L2
-
- ;----- must send string to STDOUT now
-
- CLR CH
- MOV CL, [SI-1] ; load length of string
- JCXZ DE_L2
-
- CLD
- DE_L1:
- LODSB
- CALL DISPLAY_COMPLEX
- LOOP DE_L1
-
- DE_L2:
- MOV AL, CR
- CALL DISPLAY_CHAR
- RET
- DEVICE_EPILOGUE ENDP
-
-
- SET_CURSOR_POS PROC NEAR
-
- ;-----------------------------------------------
- ; If FULL_EDIT is ON then the cursor position
- ; on the screen is updated according to the value
- ; in CURSOR_POS.
- ; If ANSI is ON then cursor-positioning is done
- ; through ANSI-escape-sequences, else through
- ; BIOS video-routines.
- ;
- PUSH DX
- PUSH BX
- PUSH AX
- CMP FULL_EDIT, ON
- JNE SCP_LX
- MOV DX, CURSOR_POS
-
- CMP ANSI, ON
- JE SCP_L1
-
- ;----- cursor positioning through BIOS
- ; function no. 2, DX = cursor-pos
- ;
- MOV BH, VIDEO_PAGE
- MOV AH, 2
- INT 10H
- JMPS SCP_LX
-
- SCP_L1:
-
- ;----- cursor positioning through ANSI
- ; output ANSI-sequence <esc>[<col>;<row>f
- ; Note: ANSI row- and column-numbers are
- ; in the range: 1 .. MaxRow/MaxCol
- ;
- MOV AL, ESCAPE
- CALL WRITE_CHAR ; <esc>
- MOV AL, '['
- CALL WRITE_CHAR ; [
- MOV AL, DH ; print row number
- INC AL
- CLR AH ;
- CALL PRINT_NUM ;
- MOV AL, ';' ; ;
- CALL WRITE_CHAR
- MOV AL, DL ; print column number
- INC AL
- CLR AH ;
- CALL PRINT_NUM ;
- MOV AL, 'f' ; f
- CALL WRITE_CHAR
- SCP_LX:
- POP AX
- POP BX
- POP DX
- RET
- SET_CURSOR_POS ENDP
-
-
- SET_CURSOR_TYPE PROC NEAR
-
- ;----------------------------------------------------------------
- ; Set cursor shape to value in variable CURSOR_TYPE.
- ; This can only be done through BIOS-VIDEO call so
- ; full edit mode must be ON and ANSI mode OFF
- ;
-
- CMP FULL_EDIT, ON
- JNE SCT_L2
- CMP ANSI, OFF ; no cursor type change
- JNE SCT_L2 ; if ANSI on
- PUSH CX
- PUSH AX
- MOV CX, CURSOR_TYPE ; set proper cursor type
- CMP INSERT_TOGGLE, ON
- JNE SCT_L1 ; if insert-state
- SUB CH, INSERT_SHIFT ; make larger cursor
- SCT_L1:
- AND CH, CURSOR_MASK
- MOV AH, 01
- INT 10H
- POP AX
- POP CX
- SCT_L2:
- RET
- SET_CURSOR_TYPE ENDP
-
- ANSI_REPLY PROC NEAR
-
- ;-------------------------------
- ; get reply from ANSI-driver
- ; must be of the form <esc>[#;#R<cr>
- ; out: DX=#;#
- ;
- PUSH CX
- PUSH BX
-
- GET_CHAR ;
- CMP AL, ESCAPE ; <esc> ?
- JNE AR_LX
- GET_CHAR
- CMP AL, '[' ; [
- JNE AR_LX
-
- MOV BL, ';' ; get first # (row)
- CLR CX
- AR_L1: ; CX = intermediate number
- GET_CHAR
- CMP AL, BL ;
- JE AR_L3 ;
- CMP AL, '9' ; read number and convert
- JA AR_LX ;
- SUB AL, '0' ;
- JB AR_LX ;
- XCHG CX, AX
- PUSH DX
- MUL TEN
- POP DX
- JNC AR_L2 ; test for overflow
- OR AX, TEN ; do something to reset Z-flag
- JMPS AR_LX
- AR_L2:
- CLR CH ; add new digit
- ADD AX, CX
- XCHG CX, AX
- JMP AR_L1
-
- AR_L3:
- DEC CL ; 1 .. Max --> 0 .. Max-1
- CMP BL, 'R' ; read second # (column)
- JE AR_L4
- MOV DH, CL
- MOV BL, 'R'
- CLR CX
- JMP AR_L1
-
- AR_L4:
- MOV DL, CL
-
- AR_LX:
- GET_CHAR ; wait for Carriage Return
- CMP AL, CR ;
- JNE AR_LX ;
-
- POP BX
- POP CX
- RET
- ANSI_REPLY ENDP
-
-
- SECOND_CODE_TABLE LABEL BYTE
-
- ;----- table of extended ascii-codes
- ;
-
- DB INSERT
- DB DELETE
- DB CURSOR_LEFT
- DB CURSOR_RIGHT
- DB PREV_LINE
- DB NEXT_LINE
- DB CURSOR_BEGIN
- DB CURSOR_END
- DB F1
- DB F2
- DB F3
- DB F4
- DB F5
- DB F6
- DB F7
- DB CTRL_LEFT
- DB CTRL_RIGHT
- DB CTRL_HOME
- DB CTRL_END
- DB CTRL_PGUP
- DB CTRL_PGDN
- DB SHIFT_F5
- DB SHIFT_F6
- DB ALT_1
- DB ALT_2
- DB ALT_3
- DB ALT_4
- DB ALT_5
- DB ALT_6
- DB ALT_7
- DB ALT_8
- DB ALT_9
- DB ALT_0
- DB 00 ; end of table
-
- CODE_TABLE_LENGTH = $ - OFFSET SECOND_CODE_TABLE
-
- ;----- ECJT = Extended Code Jump Table
- ;
-
- ECJT LABEL WORD
- DW MAIN_LOOP_RETURN
- DW ALT_DIGIT ; get old string
- DW ALT_DIGIT
- DW ALT_DIGIT
- DW ALT_DIGIT
- DW ALT_DIGIT
- DW ALT_DIGIT
- DW ALT_DIGIT
- DW ALT_DIGIT
- DW ALT_DIGIT
- DW ALT_DIGIT
-
- DW SHIFT_F6_R ; cursor shape control
- DW SHIFT_F5_R ; for INSERT-mode
-
- DW CTRL_PGDN_R ; cursor-bottom up
- DW CTRL_PGUP_R ; cursor-top up
- DW CTRL_END_R ; cursor-bottom down
- DW CTRL_HOME_R ; cursor-top down
- DW CTRL_RIGHT_R ; cursor up
- DW CTRL_LEFT_R ; cursor down
-
- DW F7_R ; zero-byte in string
- DW F6_R ; control-Z in string
- DW F5_R ; add string to buffer
- DW F4_R ; erase from begin to cursor
- DW F3_R ; erase from cursor to end
- DW F2_R ; word right
- DW F1_R ; word left
-
- DW CURSOR_END_R
- DW CURSOR_BEGIN_R
- DW NEXT_LINE_R
- DW PREV_LINE_R
- DW CURSOR_RIGHT_R
- DW CURSOR_LEFT_R
- DW DELETE_R
- DW INSERT_R
-
- PAGE
-
- ;#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-
- ;#
- ;# *** Data structure to maintain a buffer of previous strings ***
- ;#
- ;#
- ;# ___/------ STR_BUF_START
- ;# C_TBL_START ------\ _________ |_x_|
- ;# |_________| |_x_|
- ;# |_________| |_x_|
- ;# |_________| |_x_|
- ;# C_TBL_HEAD ------>|_________|-------\ |_x_|
- ;# |_________|----\ \ |_x_|
- ;# |_________| \ \-------> |_x_|
- ;# |_________| \ |_y |
- ;# |_________| \ |_y |
- ;# C_TBL_TAIL ------>|_________|-- \ \ |_y_|
- ;# |_________| \ \ |_y_|
- ;# |_________| \ \ |_y |
- ;# C_TBL_END ---------/ \ \-----> |_y_|
- ;# \ ~ ~
- ;# C-table \ ~_ _~
- ;# \ |_z_|
- ;# \ |_z_|
- ;# \ |_z_|
- ;# \----> |_z_|
- ;# |___|
- ;# |___|
- ;# |___|
- ;# \------- STR_BUF_END
- ;#
- ;# string-buffer
- ;#
- ;#
- ;# The entries in C_TABLE point to the last character of a string
- ;# in STR_BUF.
- ;#
- ;# C_TBL_HEAD points to the entry in C-table which identifies the oldest
- ;# string in the string-buffer.
- ;#
- ;# C_TBL_TAIL points to the entry in C-table which points to the last
- ;# byte of free space in the string-buffer.
- ;#
- ;#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-
-
-
- STR_BUF_SIZE DW 512 ; default string-buffer
- ; size is 512
- STR_BUF_START DW ?
- STR_BUF_END DW ?
-
- ;----- pointers to mark begin and end of data in the string buffer
- ;
-
- STR_BUF_HEAD DW ?
- STR_BUF_TAIL DW ?
-
- ;----- table of pointers to strings in string buffer
- ;
- ; pointers in string pointer table to locate
- ; the string currently being processed
- ;
- ; C_TBL_HEAD identifies the oldest string in STR_BUF
- ; C_TBL_TAIL points to the last free byte in STR_BUF, i.e. the byte
- ; before the begin of the string pointed to by C_TBL_HEAD
- ;
-
-
- C_TBL_SIZE DW 60 ; default 30 commands
-
- C_TBL_START DW ?
- C_TBL_END DW ?
-
- C_TBL_HEAD DW ?
- C_TBL_TAIL DW ?
-
- CURRENT DW ? ; identifies the string current-
- ; ly being edited
-
- ;************************************************************
- ; Next are a couple of routines to handle pointer-
- ; updating for the cyclic buffers defined above.
- ; Pointers are passed in the BX register
- ; BX is advanced to the next or previous table-item.
- ;************************************************************
-
- SCROLLUP_TBL PROC NEAR
- CMP BX, C_TBL_START ; at start of table?
- JNE SUT_L1 ; no: then go update pointer
- MOV BX, C_TBL_END ; yes: scroll to end of
- ; table first
- SUT_L1:
- DEC BX ;
- DEC BX ; pointer to previous entry
- RET
- SCROLLUP_TBL ENDP
-
-
- SCROLLDO_TBL PROC NEAR
- INC BX ; pointer to next entry
- INC BX ;
- CMP BX, C_TBL_END ; past end?
- JNE SDT_L1 ; no: all is well
- MOV BX, C_TBL_START ; yes: back to start of table
-
- SDT_L1:
- RET
- SCROLLDO_TBL ENDP
-
-
-
- BEEP PROC NEAR
-
- ;----------------------------------------------
- ; Buffer full/error beep
- ;
-
- PUSH CX
- PUSH AX
-
- MOV AL, 10010110B ; select Timer 2, low order Count
- OUT 43H, AL
- CLR AL ; set low order Count
- JMP $+2 ; allow for AT pecularities
- OUT 42H, AL ; (slow 8053-chip)
-
- MOV AL, 10100110B ; select Timer 2, high order Count
- OUT 43H, AL
- MOV AL, 3 ; pitch
- JMP $+2
- OUT 42H, AL ; set high order Count
-
- IN AL, 61H
- MOV AH, AL ; save value
- OR AL, 03H ; turn speaker on
- JMP $+2
- OUT 61H, AL
-
- MOV CX, 20000 ; beep length
-
- BRRR:
- LOOP BRRR
-
- MOV AL, AH ; restore old value
- OUT 61H, AL
-
- POP AX
- POP CX
- RET
- BEEP ENDP
-
- WRITE_CHAR PROC NEAR
-
- ;------------------------------------------
- ; Display character in AL via OS call 2
- ; or through BIOS TTY routine 0EH
- ; (necessary at initialization)
- ;
-
- PUSH AX
- CMP BIOS_TTY_SW, ON
- JNE W_CH_L1
- MOV AH, 0EH ; TTY-command
- INT 10H ; video-BIOS-routine
- JMPS W_CH_LX
-
- W_CH_L1:
- PUSH DX
- MOV DL, AL ; deliver in DL
- MOV AH, 2 ; function number
- INT 21H
- POP DX
-
- W_CH_LX:
- POP AX
- RET
- WRITE_CHAR ENDP
-
- PRINT PROC NEAR
-
- ;-------------------------------------------------------------
- ; This routine displays a string a string of characters on
- ; the crt-screen.
- ; The string is assumed to start at address DS:SI
- ; and must end with a null byte.
- ;
-
- CLD
-
- PRINT_L1:
- LODS BYTE PTR CS:[SI]
- OR AL, AL ; load bytes until
- JZ PRINT_L2 ; a zero is read
- CALL WRITE_CHAR
- JMP PRINT_L1
-
- PRINT_L2:
- RET
- PRINT ENDP
-
- PRINT_NUM PROC NEAR
-
- ;---------------------------------------
- ; Convert to ascii and display number
- ; in: AX: unsigned integer
- ;
- ;
- PUSH DX
- PUSH CX
- PUSH BX
- MOV BX, 10 ; BX = divisor
- CLR CX ; CX = digit count
-
- PR_N_L1:
- CLR DX ; DX:AX = dividend
- DIV BX
- PUSH DX ; remainder on stack
- INC CX ; keep count
- OR AX, AX ; quotient = 0 ?
- JNE PR_N_L1 ; if not, compute next digit
-
- PR_N_L2:
- POP AX ; get digits from stack
- ADD AL, '0' ; convert to ascii
- CALL WRITE_CHAR ; and display
- LOOP PR_N_L2 ;
-
- POP BX
- POP CX
- POP DX
- RET
- PRINT_NUM ENDP
-
- PAGE
-
- DISPLAY_CHAR PROC NEAR
-
- ;---------------------------------------------------------------
- ; Display character in AL.
- ; Update cursor data.
- ;
-
- CALL WRITE_CHAR
-
- CMP AL, CR
- JNE DCH_L1
-
- ;----- carriage return
- ;
- MOV CURSOR_COL, 0
- RET
-
- DCH_L1:
- CMP AL, LF
- JNE DCH_L3
-
- ;----- line feed
- ;
- CMP CURSOR_ROW, MAX_ROW - 1
- JE DCH_L2
- INC CURSOR_ROW
-
- DCH_L2:
- RET
-
- DCH_L3:
- CMP AL, BACKSPACE
- JNE DCH_L5
-
- ;----- backspace
- ;
- DEC CURSOR_COL ; cursor one left
- JNS DCH_L4 ; if < 0
- MOV AL, MAX_COL ; wrap back to previous row
- ADD CURSOR_COL, AL ;
- DEC CURSOR_ROW
- CALL SET_CURSOR_POS ; must set cursor explicitly
-
- DCH_L4: ; for wrap back
- RET
-
- DCH_L5:
-
- ;----- other characters
- ;
-
- MOV AX, STR_END_POS ; AX := difference between
- SUB AX, CURSOR_POS ; STR_END and CURRENT
- PUSH AX
- INC CURSOR_COL
- MOV AL, MAX_COL ; increment column count
- CMP CURSOR_COL, AL ; if at end move to next line
- JB DCH_L6 ;
- MOV CURSOR_COL, 0 ;
- CMP CURSOR_ROW, MAX_ROW - 1 ; on last row ?
- JE DCH_L6 ; yes, don't increment ROW
- INC CURSOR_ROW ; because of scrolling
-
- DCH_L6:
- POP AX
- OR AX, AX ; update STR_END_POS
- JNZ DCH_L7 ; if necessary
- MOV AX, CURSOR_POS
- MOV STR_END_POS, AX
-
- DCH_L7:
- RET
-
- DISPLAY_CHAR ENDP
-
-
- DISPLAY_COMPLEX PROC NEAR
-
- ;**************************************************************
- ;* This procedure takes an ascii-code looks for control-code
- ;* and displays it on the screen in the proper format
- ;* in: AL : ascii-code
- ;*
- ;* Irregular service for BS and TAB
- ;*
- ;* If DEFER_DSPL is ON then display of the string being edited
- ;* is deferred until editing is complete.
- ;***************************************************************
-
- CMP DEFER_DSPL, ON
- JE DC_X
- CMP AL, 20H ; is it a control character ?
- JNB DC_NO_CTRL ;
-
- CMP AL, BACKSPACE ; control characters,
- JE DC_NO_CTRL ; handle BS and TAB different
- CMP AL, TAB ;
- JNE DC_L2 ;
-
- ;----- display TAB character, ie. display spaces until
- ; current column number = 0 (MOD 8)
- ;
-
- PUSH CX
- CLR CH
- MOV CL, CURSOR_COL ;
- OR CL, 0F8H ; CL := 8 - (CURSOR_COL MOD 8)
- NEG CL ;
-
- DC_L1:
- MOV AL, ' '
- CALL DISPLAY_CHAR
- LOOP DC_L1
- POP CX
- JMPS DC_X
-
- ;----- display control character other then TAB or BS
- ; first display a caret, then the corresponding capital
- ; ie. ascii 1 displays as: '^A'
- ;
-
- DC_L2:
- PUSH AX
- MOV AL, '^' ; display ascii-control-character
- CALL DISPLAY_CHAR
- POP AX
- OR AL, 40H ; make it readable
-
- DC_NO_CTRL:
- CALL DISPLAY_CHAR
-
- DC_X:
- RET
- DISPLAY_COMPLEX ENDP
-
-
-
- DISPLAY_TAIL PROC NEAR
-
- ;*************************************************
- ;* this routine displays the substring starting
- ;* at the character pointed to by DI, to the end
- ;* of the buffer
- ;* in: CX: number of blanks to display after the
- ;* string to blank out any remnant characters
- ;*************************************************
-
- PUSH CURSOR_POS ; save current screen position
- PUSH CX
- MOV CL, BL ; get length of substring
- SUB CL, BH ; in CX
- CLR CH
- JCXZ DT_L2 ; display specified blanks if
- ; the substring is empty
- MOV SI, DI
-
- DT_L1:
- LODSB ; get character to display
- CALL DISPLAY_COMPLEX
- LOOP DT_L1
-
- DT_L2:
- POP CX ; recover number of additional blanks
- JCXZ DT_L4
-
- DT_L3:
- MOV AL, ' ' ;
- CALL DISPLAY_COMPLEX ;
- LOOP DT_L3
-
- DT_L4:
- POP CX ; recover screen position
- MOV AL, CH ; AL := (OLD)STR_END_ROW
- SUB CX, CURSOR_POS ;
- NEG CX ; !! CX := CURSOR_POS - (OLD)STR_END_POS
- SUB AL, CURSOR_ROW
- NEG AL ; AL := CURSOR_ROW - (OLD)STR_END_ROW
- MOV AH, MAX_COL ; sofar we pretended each row is 256
- NEG AH ; characters long, so now we must
- MUL AH ; compensate for this by subtracting
- SUB CX, AX ; (256 - characters/column)*ROW_diff.
- ;
- JCXZ DT_L6
-
- DT_L5:
- MOV AL, BACKSPACE ; use as backspace count
- CALL DISPLAY_COMPLEX ; move cursor back
- LOOP DT_L5
-
- DT_L6:
- RET
- DISPLAY_TAIL ENDP
-
-
- MOVE_TAIL_LEFT PROC NEAR
-
- ;***************************************************
- ;* routine to move the substring starting right of
- ;* the current cursor position, pointed to by DI,
- ;* one position to the left, overwriting the current
- ;* cursor position
- ;* none of the pointers are updated
- ;***************************************************
-
- PUSH CX
- PUSH DI
- CLR CH ;
- MOV CL, BL ; get length of substring
- SUB CL, BH ; in CX
- DEC CX
- JNA MTL_LX ; test for non-empty substring
-
- MOV SI, DI ;
- INC SI ; SI at first item to move
- CLD ; count forward
- REP MOVSB ;
-
- MTL_LX:
- POP DI
- POP CX
- RET
- MOVE_TAIL_LEFT ENDP
-
-
- MOVE_TAIL_RIGHT PROC NEAR
-
- ;***************************************************
- ;* routine to move the substring starting at
- ;* the current cursor position, pointed to by DI,
- ;* one position to the right.
- ;* none of the pointers are updated
- ;***************************************************
-
- PUSH CX
- PUSH DI
- CLR CH ;
- MOV CL, BL ; length of substring in CX
- SUB CL, BH ;
- JCXZ MTR_LX ; no business for empty string
-
- ADD DI, CX ; DI one past end string
- MOV SI, DI
- DEC SI ; SI at end string
- STD ; count backward
- REP MOVSB ;
-
- MTR_LX:
- POP DI
- POP CX
- RET
- MOVE_TAIL_RIGHT ENDP
-
-
- BACK_TAB PROC NEAR
-
- ;************************************************************
- ;* Compute number of backspaces needed to remove a TAB
- ;* at the current cursor position.
- ;* It is assumed that string pointers are consistent
- ;* i.e. DI points to position of TAB to be removed
- ;* and BL, BH give length of whole string and prefix resp.
- ;* required number = 8 - (current screen colunm MOD 8)
- ;*
- ;* out: CL: equivalent number of spaces for TAB in question
- ;************************************************************
-
- PUSH DI ; save current string index
- PUSH DX ; save string length
- DEC DI ; position on previous character
- CLR CH
- MOV CL, BH ; CX := prefix length
- MOV DH, 07H
- MOV AL, 20H
- JCXZ BT_3
- STD ; scan downwards through prefix
-
- BT_1:
- SCASB
- JBE BT_2 ; control character ?
- CMP BYTE PTR ES:[DI+1], TAB ;
- JE BT_4 ; if tab then exit loop (we certainly are
- ; at screen position which equals 0 (MOD 8) )
- DEC DH
-
- BT_2:
- LOOP BT_1
- ; here: CL = length to penultimate tab
- ; or zero (if no tab)
- BT_3: ; and: DH = - (no of carets)
- SUB DH, STR_START_COL ; DH := - carets - STR_START_COL
-
- BT_4:
- SUB DH, BH ; DH := - carets {- STR_START_COL}
- ; - total
- ADD CL, DH ; CL := - carets {- STR_START_COL}
- ; - (length since penultimate tab)
- AND CL, 07H ; CL := 8 - ((-CL) MOD 8)
- INC CL ;
- CLD ; reset direction flag
- POP DX ; restore string length
- POP DI ; and string index
- RET
- BACK_TAB ENDP
-
- PAGE
-
- ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
- ;
- ; K E Y B O A R D E D I T O R ( ENTRY POINT )
- ;
- ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
-
-
- FUNCTION_INT_ENTRY PROC
-
- ;****************************************************************
- ;* the address of this routine is placed in the interrupt vector
- ;* to intercept interrupt 21H. Function call 0AH is handled here,
- ;* others are passed on to DOS
- ;*
- ;****************************************************************
-
- CMP EDT_INST, OFF
- JZ FI_NOT_ACTIVE
- CMP AH, 0AH
- JZ FI_ENTRY
-
- FI_NOT_ACTIVE:
-
- ;----- go on to DOS-routines
- ;
-
- JMP CS: OLD_FUNCTION_INT
-
- FI_ENTRY:
- STI
- PUSH ES ;
- PUSH DS ;
- PUSH BP ;
- PUSH DI ;
- PUSH SI ; save registers
- PUSH DX ;
- PUSH CX ;
- PUSH BX ;
- PUSH AX
- CALL SETSTACK ; use own stack
-
- CALL DEVICE_PROLOGUE
-
- MOV AX, DS ; make ES point to buffer-
- MOV ES, AX ; segment also
- MOV SI, DX
- CLD
- LODSW ; get length of the passed buffer
- PUSH SI ; save address of start of actual string
- OR AL, AL ; if length = zero return
- JZ FI_EXIT
-
- MOV DL, AL ; DL will contain the string's
- DEC DL ; maximum length, without the
- ; final Carriage Return
- MOV CL, AH
- CLR CH
- MOV BX, CX
- JCXZ FI_RESTART
- CMP BYTE PTR DS:[SI+BX], CR ; is input-string
- ; terminated properly ?
- JNE FI_RESTART ; no, ignore
- CALL STR_BUF_INSERT
-
- FI_RESTART:
- MOV DH, STR_START_COL ; initialize column counter
- MOV CURSOR_COL, DH
- CALL SET_CURSOR_POS
-
- MOV INSERT_TOGGLE, OFF ; overwrite mode
- CALL SET_CURSOR_TYPE
-
- CLR BL ; BL will contain the current number
- ; of characters in the string
- CLR BH ; BH will contain the number of
- ; characters up to but not including
- ; the cursor position
- POP DI ; DI is the current position in the
- ; buffer
- PUSH DI ; address back on stack
- GET_CHAR ; get first character
- CMP AL, LF ; if first character is a
- JE MAIN_LOOP ; line-feed then throw it away
- JMP MAIN_ENTRY ; enter main loop at main
- ; entrance-point
-
- FI_EXIT:
- POP SI
- CALL DEVICE_EPILOGUE
-
- CALL RESETSTACK ; restore user stack
-
- POP AX ;
- POP BX ;
- POP CX ;
- POP DX ;
- POP SI ; restore registers
- POP DI ;
- POP BP ;
- POP DS ;
- POP ES ;
- IRET
-
- FUNCTION_INT_ENTRY ENDP
-
-
- MAIN_LOOP PROC NEAR
-
- GET_CHAR
-
- MAIN_ENTRY:
- CMP AL, ACK
- JE MAIN_LOOP ; no ACK's
-
- LEA BP, MAIN_LOOP ; set up return address on
- PUSH BP ; the stack for all routines
- ; wishing to return to MAIN_LOOP
- CMP AL, LF
- JE LF_RN ;
- CMP AL, BACKSPACE ; find out whether one
- JE BACKSPACE_RN ; of these special
- ; CMP AL, ESCAPE ; characters was read
- ; JE ESCAPE_RN ;
- CMP AL, CTRL_U
- JE ESCAPE_RN
- CMP AL, CR ; search for editing
- JE CR_R ; keys
- CMP AL, CTRL_W
- JE CW_RN
- CMP AL, 0 ;
- JE EXTENDED_ASCIIN ;
-
-
- ;----- a character must be inserted in the current string
- ;
-
- M_L1:
- CMP INSERT_TOGGLE, ON ; insert- or
- JNE OVERWRITE ; overwrite-mode?
-
- CMP BL, DL ; is buffer full ?
- JB M_L2 ; no: put this character
- CALL BEEP ; in the buffer
- RET ; else: ring the bell
-
- M_L2:
- CALL MOVE_TAIL_RIGHT ; make room for new character
- CLD ;
- STOSB ; insert the new character
- INC BL ; update length
- INC BH ; and cursor position
- CLR CX
-
- ;---- display updated string
- ; also postlude for OVERWRITE routine
- ;
-
- M_L3:
- CALL DISPLAY_COMPLEX ; display the new character
- CALL DISPLAY_TAIL ; and those to the right of it
- M_L4:
- RET
-
-
- OVERWRITE:
- CMP BH, BL ; if cursor position
- JB M_L6 ; at end, then check for
- CMP BL, DL ; full buffer
- JB M_L5 ;
- CALL BEEP ;
- RET ;
-
- M_L5: ;
- INC BL
- M_L6: ; if a character is added at
- INC BH ; the end, update total
- ; length also
- CLR CX
- CMP BH, BL ; at end of string ?
- JE M_L8 ; yes, just add it
-
- ;----- must overwrite some character
- ; get character to overwrite in AH
- ; character to overwrite with still in AL
-
- MOV AH, ES:[DI]
-
- CMP AH, TAB ; is it a TAB ?
- JNE M_L7 ; go if not
-
- ;----- get rid of TAB
- ;
-
- PUSH AX
- DEC BH ; BACKTAB expects string
- CALL BACK_TAB ; pointers set up for tab prefix
- INC BH ; restore prefix length
- DEC CX
- POP AX
- JMPS M_L8
-
- M_L7:
- CMP AH, 20H ; if control character
- JAE M_L8 ; then check character to write
- INC CX
- CMP AL, TAB ; tab can also show as one space
- JE M_L8
- CMP AL, 20H
- JNB M_L8 ; if not cntr-char
- DEC CX ; display extra space
-
- ;----- character to buffer
- ;
-
- M_L8:
- CLD
- STOSB
- JMP M_L3 ; go update screen
-
-
-
- ;----- boost some conditional jumps
- ;
-
- LF_RN: JMP LF_R
- BACKSPACE_RN: JMP BACKSPACE_R
- ESCAPE_RN: JMP ESCAPE_R
- CW_RN: JMP CTRL_W_R
- EXTENDED_ASCIIN:JMP EXTENDED_ASCII
-
-
- CR_R:
-
- ;----------------------------
- ; add a Carriage Return to the end of the string, set string-length byte
- ; insert in STR_BUF, and go to exit
- ; ! the carriage return character is sent to STDOUT in DEVICE_EPILOGUE
- ;
-
- CLR CH ;
- MOV CL, BL ; set DI to end of string
- SUB CL, BH ;
- ADD DI, CX ;
- STOSB ; and put carriage return there
-
- PUSH STR_END_POS
- POP CURSOR_POS
- CALL SET_CURSOR_POS
-
- POP BP ; remove return address from stack
- POP SI ; recover first-byte address
- PUSH SI
- LEA BP, FI_EXIT
- PUSH BP
-
- MOV [SI-1], BL ; store count
-
- CLR CH
- MOV CL, BL ; length in CX
-
-
- STR_BUF_INSERT:
-
- ;-----------------------------------------------------
- ; On entry CX contains the length of the string
- ; and SI points to the string's first byte.
- ; note: this code is called as a subroutine at entry
- ; and by F5_R
- ; When freeing space to insert a new string, as many of
- ; the oldest strings are removed as is necessary to make
- ; room for the new one. Because maximum string length is
- ; is 255 and minimum length of strings in the buffer is 1
- ; it follows that no more than 255 should ever be removed.
- ; Therefore, a counter is maintained during the the loop
- ; which removes old strings from the buffer to prevent an
- ; accidentally corrupted data-structure from causing an
- ; endless loop here.
- ;
-
- JCXZ SBI_L17 ; if string-length = 0 don't insert
-
- ;----- load register DI with address of last byte before
- ; begin of free space in STR_BUF
- ;
-
- MOV BX, C_TBL_TAIL ;
- MOV CURRENT, BX ; must update CURRENT
- CMP BX, C_TBL_HEAD
- JE SBI_L1
- CALL SCROLLUP_TBL
-
- SBI_L1:
- MOV DI, CS:[BX]
- JE SBI_L18 ; if table empty, we should not enter
- ; compare routine
- ; ! proc SCROLLUP does not set Z-flag
-
- ;----- determine whether string is different from previous
- ;
-
- PUSH DI
- MOV AX, DI
- CMP BX, C_TBL_HEAD ; wrap pointers if appropriate
- JNE SBI_L11 ;
- MOV BX, C_TBL_TAIL ;
- JMPS SBI_L12
-
- SBI_L11:
- CALL SCROLLUP_TBL
-
- SBI_L12:
- MOV DI, CS:[BX]
- SUB AX, DI ; compute length of previous string
- JAE SBI_L13 ;
- ADD AX, STR_BUF_SIZE; string can wrap in STR_BUF
-
- SBI_L13:
- CMP AX, CX ; compare lengths
- JNE SBI_L16 ; go if not equal
-
- PUSH ES ; save registers altered
- PUSH SI ; when comparing strings
- PUSH CX ;
-
- MOV AX, CS ; set up addressing
- MOV ES, AX ;
- CLD ;
- INC DI ;
-
- SBI_L14:
- CMP DI, STR_BUF_END ; compare string in
- JNE SBI_L15 ; STR_BUF with input string
- MOV DI, STR_BUF_START ;
- ;
- SBI_L15: ;
- CMPSB ;
- LOOPZ SBI_L14 ;
-
- POP CX ; restore registers
- POP SI ;
- POP ES ;
-
- SBI_L16:
- POP DI
- JNE SBI_L18
-
- SBI_L17:
- RET ; return if strings proved equal
-
- SBI_L18:
-
- ;----- next get an entry in C_TBL for the new string
- ;
-
- MOV BX, C_TBL_TAIL ; C_TBL_TAIL is moved to make room,
- MOV AX, CS:[BX] ; save its contents first, ...
- PUSH DI ;
- ADD DI, CX ; calculate where new string
- CMP DI, STR_BUF_END ; will end in STR_BUF,
- JB SBI_L2 ;
- SUB DI, STR_BUF_SIZE
-
- SBI_L2:
- MOV CS:[BX], DI ; ... then fill it with new length
- POP DI
-
- CLR DH ; use as retry count for loop
- ; starting at label SBI_L3
-
- CALL SCROLLDO_TBL ;
- MOV C_TBL_TAIL, BX ; new tail
- MOV CURRENT, BX ; and new current also
- CMP BX, C_TBL_HEAD ; collision with head ?
- JNE SBI_L3 ; no, go and restore contents
-
- PUSH BX ; yes, remove oldest string
- CALL SCROLLDO_TBL ; space is automatically deallocated
- MOV C_TBL_HEAD, BX ; by moving the pointers
- POP BX ; BX back at tail
-
- MOV AX, CS:[BX] ; new value for end of free space
-
- SBI_L3:
- MOV CS:[BX], AX ; set new C_TBL_TAIL to current
- ; end of free space
-
- ;----- determine if there is enough free space to hold the new
- ; string and keep removing old entries until there is
- ;
-
- SUB AX, DI ; AX contains current end of free space
- JA SBI_L4 ; AX=DI means STR_BUF is empty (free-
- ; pointer = last-string-pointer)
- ADD AX, STR_BUF_SIZE; undo wrap-around effect
-
- SBI_L4:
- CMP AX, CX ; is there enough ?
- JA SBI_L5 ; yes, go and do the transfer
- ; note: always keep one byte free
- DEC DH ; how many times did we try ?
- JZ SBI_ERR ; if zero too many: something is wrong
- ; exit with beep, also RESET is called
- PUSH BX ; no, remove another entry from TABLE
- MOV BX, C_TBL_HEAD
- MOV AX, CS:[BX] ; get address of last byte occupied
- CALL SCROLLDO_TBL ; by this entry's string
- MOV C_TBL_HEAD, BX ; new head of the table
- POP BX ;
-
- JMP SBI_L3 ; try again
-
- ;----- now we are ready for the transfer
- ;
-
- SBI_L5:
- MOV AX, CS ;
- MOV ES, AX ; set up target pointers
- INC DI ;
- CLD ; count in right direction
-
- SBI_L6:
- CMP DI, STR_BUF_END ;
- JNE SBI_L7 ; wrap-around if neccesary
- MOV DI, STR_BUF_START
-
- SBI_L7:
- MOVSB ; store bytes of string
- LOOP SBI_L6 ; until done (CX=0)
-
- MOV AX, DS ;
- MOV ES, AX ; restore ES
-
- SBI_LX:
- RET
-
- SBI_ERR:
- CALL RESET_EDT
- CALL BEEP
- RET
-
- LF_R:
- CALL CURSOR_END_R
- MOV AL, LF
- CALL DISPLAY_CHAR
- MOV AL, CR
- CALL DISPLAY_CHAR
- RET
-
-
- BACKSPACE_R:
- OR BH, BH ; is cursor at begin of string ?
- JZ BS_L1 ; yes, then nothing to do
- CALL CURSOR_LEFT_R ; otherwise, delete the character
- CALL DELETE_R ; left of the current cursor-position
- BS_L1: RET
-
-
-
- ;---------------------------------
- ; abandon current string and start editing a new one
- ESCAPE_R: CALL CURSOR_BEGIN_R
- CALL F4_R
- CALL CURSOR_END_R
- ADD SP, 2 ; discard return address on stack
- JMP FI_RESTART ; redo from scratch
-
- ; Delete previous whitespace, or alphanumerics
- CTRL_W_R: CALL BACKSPACE_R ; delete a character in any case
- OR BH, BH ; at beginning of string?
- JZ CW_RET ; yes, done
- CMP BYTE PTR [DI-1],' ' ; tab or...
- JZ CTRL_W_BL
- CMP BYTE PTR [DI-1],' ' ; blank or...
- JZ CTRL_W_BL
- CTRL_W_LOOP: CMP BYTE PTR [DI-1],'0' ; numeric
- JB CW_RET
- CMP BYTE PTR [DI-1],'9' ; ...
- JBE CTRL_W_NB
- CMP BYTE PTR [DI-1],'A' ; or alpha, continue deletion
- JB CW_RET
- CMP BYTE PTR [DI-1],'Z'
- JBE CTRL_W_NB
- CMP BYTE PTR [DI-1],'a'
- JB CW_RET
- CMP BYTE PTR [DI-1],'z'
- JBE CTRL_W_NB
- CW_RET: RET
-
- CTRL_W_BL: CALL BACKSPACE_R ; Flush previous character
- OR BH,BH ; at beginning?
- JZ CW_RET ; Yes...
- CMP BYTE PTR [DI-1],' ' ; tab or...
- JZ CTRL_W_BL
- CMP BYTE PTR [DI-1],' ' ; blank or...
- JZ CTRL_W_BL
- JMP CW_RET
-
- CTRL_W_NB: CALL BACKSPACE_R ; delete a character in any case
- OR BH, BH ; at beginning of string?
- JZ CW_RET ; yes, done
- JMP CTRL_W_LOOP
-
- EXTENDED_ASCII:
- GET_CHAR
- PUSH ES ; the second code is in AL now
- PUSH DI
- MOV DI, CS
- MOV ES, DI
- LEA DI, SECOND_CODE_TABLE
- MOV CX, CODE_TABLE_LENGTH
- CLD
- CLI ; we need CX after scan
- REPNE SCASB ; search for extended code in table
- STI
- SHL CX, 1 ; CX is now offset in jump-table
- MOV BP, CX
- POP DI
- POP ES
- JMP [BP+ECJT]
-
- INSERT_R:
-
- ;----- flip the insert-toggle
- ;
-
- NOT INSERT_TOGGLE
-
- CALL SET_CURSOR_TYPE
- RET
-
-
- DELETE_R:
-
- ;----- delete the character under the cursor
- ;
-
- CMP BL, BH ; if cursor at end
- JE DR_L2 ; then nothing to delete
-
- MOV AH, ES:[DI] ; remember victim for display update
- CALL MOVE_TAIL_LEFT ; remove from buffer
- DEC BL ; update total length
-
- ;----- next update display
- ;
-
- MOV CX, 1 ; at least one character to erase
-
- CMP AH, 20H ; control character ?
- JAE DR_L1 ;
-
- INC CX ; yes, erase the caret too
- CMP AH, TAB ; beware of the TAB
- JNE DR_L1 ; if TAB then some calculation required
- ; to determine shift of display
- CALL BACK_TAB
-
- DR_L1:
- CALL DISPLAY_TAIL
-
- DR_L2:
- RET
-
- CURSOR_LEFT_R:
-
- ;----- move current cursor position one to the left
- ;
-
- OR BH, BH
- JZ CL_ATBEGIN ; cursor at begin of string
- DEC DI ; update pointers
- DEC BH ;
-
- ;----- update display
- ;
-
- MOV CX, 1 ; set up for one backspace
-
- MOV AH, [DI] ; get character under cursor
- CMP AH, 20H ; if control-character then
- JAE CL_BS ; two backspaces are required
-
- INC CL ; if ctrl-char then two backspaces
- CMP AH, TAB ; exception: tab-character
- JNE CL_BS ;
-
- CALL BACK_TAB ; compute number of backspaces
- ; needed for this tab (returned in CL;)
-
- CL_BS:
- MOV AL, BACKSPACE
- CALL DISPLAY_COMPLEX
- LOOP CL_BS
- RET
-
- CL_ATBEGIN:
- CALL BEEP
- RET
-
-
- CURSOR_RIGHT_R:
-
- ;----- move current cursor position one to the right
- ;
-
- CMP BL, BH
- JE CR_AT_END ; cursor at end of string
- MOV AL, [DI] ; get character under cursor
- INC DI ; update pointers
- INC BH ;
-
- ;----- update display
- ;
-
- CMP AL, 20H
- JB CRR_L2
-
- ;----- non-control ascii character, so
- ; cursor must move right one position
- ; see if this can be done by cursor control
- ; if not then redisplay character
- ;
-
- CMP FULL_EDIT, ON
- JNE CRR_L2
-
- MOV AX, CURSOR_POS
- INC AL
- CMP AL, MAX_COL
- JB CRR_L1
- CLR AL
- CMP AH, MAX_ROW - 1
- JE CRR_L1
- INC AH
-
- CRR_L1:
- MOV CURSOR_POS, AX
- CALL SET_CURSOR_POS
- RET
-
- CRR_L2:
-
- ;----- move cursor right by redisplaying the character
- ; which is under cursor now
- ;
-
- CALL DISPLAY_COMPLEX
- RET
-
- CR_AT_END:
- CALL BEEP
- RET
-
- PREV_LINE_R:
-
- ;------------------------------
- ; empty the current buffer and get the one less
- ; recent string from the string buffer
-
- MOV BP, SP ; need access to buffer address
- ; which is saved on the stack
- PUSH STR_END_POS ; save current end of string on screen
- CALL CURSOR_BEGIN_R
-
- ;----- next find a new string to be edited
- ;
-
- MOV AX, C_TBL_HEAD ; take a look in the
- CMP AX, C_TBL_TAIL ; string pointer table
- JE PNL_EMPTY ; no string there
- ; proceed with empty string
- MOV BX, CURRENT ;
- CMP BX, AX ; determine previous entry
- JNE PL_L1 ; in TABLE,
- MOV BX, C_TBL_TAIL ;
- PL_L1:
- CALL SCROLLUP_TBL ;
- MOV CURRENT, BX ; and make it the current one
- MOV CX, CS:[BX] ;
- CMP BX, AX ; determine length of this
- JNE PL_L2 ; candidate by scrolling up
- MOV BX, C_TBL_TAIL ; another entry ...
- JMPS PL_L3 ;
- PL_L2:
- CALL SCROLLUP_TBL ;
- PL_L3: ;
- MOV SI, CS:[BX] ; ... and subtracting the
-
- PNL_L1:
- SUB CX, SI ; addresses of the strings'
- JA PNL_L2 ; last bytes.
- ADD CX, STR_BUF_SIZE; we have wrapped around in STR_BUF
- PNL_L2:
- JCXZ PNL_EMPTY
- MOV BL, CL ; CL now contains the candidate's
- MOV BH, CL ; length.
- CMP DL, CL ; initialize string-pointers
- JNB PNL_L3
-
- CALL BEEP ; if too long ring bell twice (as long)
- CALL BEEP
-
- PNL_EMPTY:
- ADD SP, 4 ; discard return address and
- ; EOS which are on the stack
- JMP FI_RESTART
-
-
- ;----- the new string can be transferred now
- ;
-
- PNL_L3:
- MOV DI, [BP+2] ; get address of target buffer
-
- INC SI ; set source pointer
- PNL_L4:
- CMP SI, STR_BUF_END ; wrap-around in STR_BUF
- JNE PNL_L5 ; if nessecary
- MOV SI, STR_BUF_START
- PNL_L5:
- LODS BYTE PTR CS:[SI]; do the transfer
- STOSB ;
- CALL DISPLAY_COMPLEX ; display this byte
- LOOP PNL_L4 ;
-
- ;-----the pointers BH, BL, and DI are properly set up now
- ; the current cursor-position is at the end of the new string
- ;
-
- ;----- compute difference in string length
- ;
-
- POP CX ; recover saved STR_END_POS
- ; of previous string
- MOV AL, CH ; AL := (OLD)STR_END_ROW
- SUB CX, CURSOR_POS ; !! CX := CURSOR_POS - (OLD)STR_END_POS
- JBE PNL_L8 ; new > old ?
- SUB AL, CURSOR_ROW ; AL := CURSOR_ROW - (OLD)STR_END_ROW
- MOV AH, MAX_COL
- NEG AH
- MUL AH ; multiply by (256 - characters/column)
- SUB CX, AX ; compensate for subtraction !!
- ; CX := (oldROW - newROW)*MAX_COL +
- ; (oldCOL - newCOL)
- PUSH CX
-
- PNL_L6:
- MOV AL, ' ' ; blank out remnant characters
- CALL DISPLAY_COMPLEX
- LOOP PNL_L6
- POP CX
-
- PNL_L7:
- MOV AL, BACKSPACE ; set cursor back
- CALL DISPLAY_COMPLEX
- LOOP PNL_L7
-
- PNL_L8:
-
- PUSH CURSOR_POS
- POP STR_END_POS
- RET ; top of stack = address MAINLOOP
-
-
-
-
- NEXT_LINE_R:
-
- ;---------------------------
- ; empty the current buffer and get the one more
- ; recent string from the string buffer
-
- MOV BP, SP ; need access to buffer address
- ; which is saved on the stack
- PUSH STR_END_POS ; save current end of string on screen
- CALL CURSOR_BEGIN_R
-
- ;----- find next string
- ;
-
- MOV AX, C_TBL_TAIL
- CMP AX, C_TBL_HEAD
- JE PNL_EMPTY ; no string found
- MOV BX, CURRENT
- MOV SI, CS:[BX] ; get current string's end
- CMP BX, AX ; current=tail ?
- JE NL_L2 ; yes, wraparound
- CALL SCROLLDO_TBL ; else, scroll down
- CMP BX, AX ; at tail now ?
- JNE NL_L3 ; no, go and update CURRENT
- MOV SI, CS:[BX] ; else, new old string's end
-
- NL_L2:
- MOV BX, C_TBL_HEAD ; wraparound
-
- NL_L3:
- MOV CURRENT, BX ; new current string
- MOV CX, CS:[BX] ; new string's end
- JMP PNL_L1 ; next check the length
-
-
- CURSOR_BEGIN_R:
-
- ;----- moves the cursor to the start of the buffer
- ;
-
- OR BH, BH ; is cursor at start ?
- JZ CBR_DONE ; if so then return
- CALL CURSOR_LEFT_R ; move one to the left
- JMP CURSOR_BEGIN_R ; and again until at start
- CBR_DONE:
- RET
-
- CURSOR_END_R:
-
- ;----- moves the cursor to the end of the buffer
- ;
-
- CMP BL, BH ; is cursor at end ?
- JE CER_DONE ; yes: return
- CALL CURSOR_RIGHT_R ; move one towards the end
- JMP CURSOR_END_R ; until done
- CER_DONE:
- RET
-
- F1_R:
-
- ;----- move cursor one word left
- ;
-
- CALL CURSOR_LEFT_R ;
- OR BH, BH ; move one character left
- JZ F1_L2 ; until a non-blank is
- CMP BYTE PTR [DI-1], ' ' ; reached
- JE F1_R ;
-
- F1_L1:
- CALL CURSOR_LEFT_R ; now move left until
- OR BH, BH ; the next blank
- JZ F1_L2 ;
- CMP BYTE PTR [DI-1], ' ' ;
- JNE F1_L1
-
- F1_L2: ;
- RET
-
-
- F2_R:
-
- ;----- move cursor one word right
- ;
-
- CALL CURSOR_RIGHT_R ;
- CMP BL, BH ; move one character right
- JE F2_L2 ; until a blank is reached
- CMP BYTE PTR [DI], ' ' ;
- JNE F2_R
-
- F2_L1:
- CALL CURSOR_RIGHT_R
- OR BH, BH ; move on until the
- JZ F2_L2 ; next non-blank
- CMP BYTE PTR [DI], ' ' ;
- JE F2_L1 ;
-
- F2_L2: ;
- RET
-
-
- F3_R:
-
- ;----- erase from begin of the string to the current cursor position
- ;
-
- CLR CH
- MOV CL, BH
- JCXZ F3_L2 ; CX=0: we are at start of string
-
- F3_L1:
- PUSH CX ; save number of characters
- CALL BACKSPACE_R ; we are going to remove
- POP CX ; recover number of characters
- LOOP F3_L1 ;
-
- F3_L2:
- RET
-
-
- F4_R:
-
- ;----- erase from the current cursor position to the end
- ;
-
- CLR CH
- MOV CL, BL
- SUB CL, BH
- JZ F4_L2
- CALL CURSOR_END_R
-
- F4_L1:
- PUSH CX
- CALL BACKSPACE_R
- POP CX
- LOOP F4_L1
-
- F4_L2:
- RET
-
-
- F5_R:
-
- ;----- insert current string in STR_BUF and start editing a fresh one
- ;
-
- MOV BP, SP ; need access to buffer address
- ; which is saved on the stack
- CALL CURSOR_END_R
- MOV AL, '@' ; show what is going to happen
- CALL DISPLAY_CHAR ;
- MOV AL, CR
- CALL DISPLAY_CHAR
- MOV AL, LF
- CALL DISPLAY_CHAR
-
- MOV SI, [BP+2] ; get source pointer from stack
- CLR CH
- MOV CL, BL
- CALL STR_BUF_INSERT
-
- ADD SP, 2 ; discard return address on stack
- JMP FI_RESTART
-
-
- F6_R:
-
- ;----- End Of File character on function-key 6
- ;
-
- MOV AL, EOF
- JMP M_L1 ; go insert this character
-
-
- F7_R:
-
- ;----- Nul on function-key 7
- ;
-
- CLR AL
- JMP M_L1 ; go insert this character
-
-
- CTRL_LEFT_R:
-
- ;----- move cursor downwards
- ;
-
- MOV AX, CURSOR_TYPE
- CMP AL, CURSOR_MASK
- JE CTRL_LR_X
- INC AL
- INC AH
- MOV CURSOR_TYPE, AX
- CALL SET_CURSOR_TYPE
- CTRL_LR_X:
- RET
-
- CTRL_RIGHT_R:
-
- ;----- move cursor upwards
- ;
-
- MOV AX, CURSOR_TYPE
- OR AH, AH
- JZ CTRL_RR_X
- DEC AL
- DEC AH
- MOV CURSOR_TYPE, AX
- CALL SET_CURSOR_TYPE
- CTRL_RR_X:
- RET
-
- CTRL_HOME_R:
-
- ;----- move cursor-top downwards
- ;
-
- MOV AX, CURSOR_TYPE
- CMP AH, CURSOR_MASK
- JE CTRL_HR_X
- INC AH
- MOV CURSOR_TYPE, AX
- CALL SET_CURSOR_TYPE
- CTRL_HR_X:
- RET
-
- CTRL_END_R:
-
- ;----- move cursor-bottom downwards
- ;
-
- MOV AX, CURSOR_TYPE
- CMP AL, CURSOR_MASK
- JE CTRL_ER_X
- INC AL
- MOV CURSOR_TYPE, AX
- CALL SET_CURSOR_TYPE
- CTRL_ER_X:
- RET
-
- CTRL_PGUP_R:
-
- ;----- move cursor-top upwards
- ;
-
- MOV AX, CURSOR_TYPE
- OR AH, AH
- JZ CTRL_PU_X
- DEC AH
- MOV CURSOR_TYPE, AX
- CALL SET_CURSOR_TYPE
- CTRL_PU_X:
- RET
-
- CTRL_PGDN_R:
-
- ;----- move cursor-bottom upwards
- ;
-
- MOV AX, CURSOR_TYPE
- OR AL, AL
- JZ CTRL_PD_X
- DEC AL
- MOV CURSOR_TYPE, AX
- CALL SET_CURSOR_TYPE
- CTRL_PD_X:
- RET
-
- SHIFT_F5_R:
-
- ;----- decrement change in INSERT cursor-shape
- ;
-
- CMP INSERT_SHIFT, 0
- JE SHIFT_F5_X
- DEC INSERT_SHIFT
- CALL SET_CURSOR_TYPE
- SHIFT_F5_X:
- RET
-
- SHIFT_F6_R:
-
- ;----- increment change in INSERT cursor-shape
- ;
-
- CMP INSERT_SHIFT, CURSOR_MASK
- JE SHIFT_F6_X
- INC INSERT_SHIFT
- CALL SET_CURSOR_TYPE
- SHIFT_F6_X:
- RET
-
-
- ALT_DIGIT:
-
- ;----- scroll up through previous strings a number of
- ; times given by the digit key which was pressed
- ; along with the ALT-key.
- ;
-
- SUB AL, ALT_1 ; make use of contiguous range of codes
- ; generated by the ALT-digit keys
- ; AL now in range 0 .. 9
- CLR CH
- MOV CL, AL
- JCXZ DA_LX ; so ALT_1 same as arrow-up
-
- PUSH BX
- MOV BX, CURRENT ; get CURRENT
-
- DA_L1:
- CMP BX, C_TBL_HEAD ; at oldest string in table ?
- JNE DA_L2 ; if so, stop, no wrap around
- CALL SCROLLDO_TBL ; and undo last scrollup
- JMPS DA_L3
-
- DA_L2:
- CALL SCROLLUP_TBL ; else one entry up
- LOOP DA_L1 ; repeat CX times
-
- DA_L3:
- MOV CURRENT, BX ; update CURRENT
- POP BX
-
- DA_LX:
- JMP PREV_LINE_R ;
-
-
-
- MAIN_LOOP_RETURN:
-
- ;----- no match in extended ascii found, return to main loop
- ;
-
- RET
-
-
-
- MAIN_LOOP ENDP
-
-
- REQ_HDR STRUC
-
- LENGTH DB ?
- UNIT DB ?
- COMMAND DB ?
- STATUS DW ?
- RESERV DB 8 DUP(?)
-
- REQ_HDR ENDS
-
- INIT_HDR STRUC
-
- DB SIZE REQ_HDR DUP(?)
- NO_UNITS DB ?
- END_ADR DD ?
- PARMS DD ?
-
- INIT_HDR ENDS
-
- IO_HDR STRUC
-
- DB SIZE REQ_HDR DUP(?)
- MEDIA DB ?
- BUFFER_ADR DD ?
- COUNT DW ?
-
- IO_HDR ENDS
-
- ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
- ;
- ; D E V I C E S T R A T E G Y ( ENTRY POINT )
- ;
- ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
-
- D_STRATEGY PROC FAR
-
- ;----- save request header address
- ;
-
- MOV REQ_HEADER_OFS, BX
- MOV REQ_HEADER_SEG, ES
- RET
-
- D_STRATEGY ENDP
-
-
- D_F_TABLE LABEL WORD ; this table contains routine addresses
- ; for the device-driver functions
-
- DW D_INIT ; 0: driver initialization
- DW D_NOP ; 1: media check
- DW D_NOP ; 2: build BPB
- DW D_IOCTL_IN ; 3: IO-control input
- DW D_INPUT ; 4: input
- DW D_NON_DSTR_IN ; 5: non-destructive input
- DW D_INPUT_STATUS ; 6: input status
- DW D_INPUT_FLUSH ; 7: input flush
- DW D_OUTPUT ; 8: output
- DW D_OUTPUT_VER ; 9: output with verify
- DW D_OUTPUT_STATUS ; 10: output status
- DW D_OUTPUT_FLUSH ; 11: output flush
- DW D_IOCTL_OUT ; 12: IO-control output
- DW D_OPEN ; 13: device open
- DW D_CLOSE ; 14: device close
- DW D_NOP ; 15: removable media
-
- D_F_TABLE_LEN = $ - D_F_TABLE
-
- ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
- ;
- ; D E V I C E I N T E R R U P T ( ENTRY POINT )
- ;
- ;-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
-
- D_INTERRUPT PROC FAR ;
- STI
- PUSH ES ;
- PUSH DS ;
- PUSH BP ; save
- PUSH DI ; registers
- PUSH SI ;
- PUSH DX ;
- PUSH CX ;
- PUSH BX ;
- PUSH AX
-
- CALL SETSTACK ; to internal stack
- MOV BIOS_TTY_SW, ON
- MOV ES, REQ_HEADER_SEG ; get request-
- MOV BX, REQ_HEADER_OFS ; header block
- MOV AL, ES: [BX].COMMAND ; get opcode
- CLR AH
- SHL AX, 1
- CMP AX, D_F_TABLE_LEN
- JAE D_ERROR
- MOV SI, AX
- JMP D_F_TABLE[SI] ; do request
-
- ;----- it is assumed that all routines preserve
- ; the ES:BX pointer to the Request Header
- ;
-
- D_ERROR:
- OR ES: [BX].STATUS, 8003H ; invalid code
-
- D_EXIT:
- OR ES: [BX].STATUS, 0100H ; status_ok
- MOV BIOS_TTY_SW, OFF
- CALL RESETSTACK ; back to
- ; callers stack
- POP AX
- POP BX
- POP CX ;
- POP DX ;
- POP SI ; restore
- POP DI ; registers
- POP BP ;
- POP DS ;
- POP ES ;
- RET
-
-
- D_INTERRUPT ENDP
-
-
- D_NOP :
- D_IOCTL_IN :
- D_INPUT :
- D_NON_DSTR_IN :
- D_INPUT_STATUS :
- D_INPUT_FLUSH :
- D_OUTPUT_STATUS :
- D_OUTPUT_FLUSH :
- D_IOCTL_OUT :
- D_OPEN :
- D_CLOSE :
- JMP D_ERROR
-
-
- INSTALL_BUF PROC NEAR
-
- ;***************************************************************
- ;* Redirect the DOS-keyboard-buffer pointers to enlarged buffer
- ;* Copy old buffer contents to the new buffer
- ;***************************************************************
-
- PUSH DS
- CMP KB_INST, ON ;
- JNE IB_L1 ; buffer is already here
- LEA SI, MSG_KB_PR ; already present message
- JMP IB_LX
- IB_L1:
- CMP KBBUFFER_SIZE, 32 ; worth the trouble ?
- JA IB_L2 ;
-
- LEA SI, MSG_KB_NO_1 ; message: no succes
- CALL PRINT
- MOV AX, KBBUFFER_SIZE
- SHR AX, 1
- CALL PRINT_NUM
- LEA SI, MSG_KB_NO_2
- JMP IB_LX
-
- IB_L2:
- ASSUME DS: DOS_DATA_AREA ;
- MOV AX, DOS_DATA_AREA ; data segment on
- MOV DS, AX ; DOS-OS Data
- CLR DI
- MOV BX, KBBUFFER
- CLI
- MOV SI, KB_HEAD ; move any data already
- IB_L3:
- CMP SI, KB_TAIL ; in the DOS-buffer to
- JE IB_L4 ; new buffer
- CMP DI, 32 ; can not copy indefinitely
- JE IB_L4 ; because new buffer overlays
- ; initialization code
- MOV AX, [SI] ;
- MOV CS: [BX+DI], AX ; transfer item
- INC DI ; keep character count
- INC DI ;
- INC SI ;
- INC SI ;
- CMP SI, DOS_BUFFER_END ; wraparound if
- JNE IB_L3 ; neccesary
- MOV SI, DOS_BUFFER_START ;
- JMP IB_L3 ;
- IB_L4:
- MOV AX, DOS_BUFFER_START
- MOV OLD_DOS_BUFFER_START, AX
- MOV AX, DOS_BUFFER_END
- MOV OLD_DOS_BUFFER_END, AX
- MOV AX, CS ;
- SUB AX, DOS_DATA_AREA ; make AX point to offset
- MOV CL, 4 ; KBBUFFER relative to
- SHL AX, CL ; segment DOS_DATA_AREA
- ADD AX, KBBUFFER ;
- MOV DOS_BUFFER_START, AX ;
- MOV KB_HEAD, AX ; change pointers to
- MOV KB_TAIL, AX ; our own buffer
- ADD KB_TAIL, DI ;
- ADD AX, KBBUFFER_SIZE ; add number of characters
- MOV DOS_BUFFER_END, AX ; taken over from old buffer
- STI
- ASSUME DS: NOTHING
-
- MOV KB_INST, ON ; presence-flag on
- LEA SI, MSG_KB_IN ; message: succes
- CALL PRINT
- LEA SI, MSG_KB_1 ; give size of buffer
- CALL PRINT
- MOV AX, KBBUFFER_SIZE
- SHR AX, 1
- CALL PRINT_NUM
- LEA SI, MSG_KB_2
-
- IB_LX:
- CALL PRINT ;
- POP DS
- RET
- INSTALL_BUF ENDP
-
-
-
- UNINSTALL_BUF PROC NEAR
-
- ;************************************************
- ;* Restore original keyboard buffer pointers
- ;*************************************************
-
- PUSH DS
-
- CMP KB_INST, OFF
- JE UB_L1
-
- ASSUME DS: DOS_DATA_AREA ;
- MOV AX, DOS_DATA_AREA ; data segment on
- MOV DS, AX ; DOS-OS Data
- CLI
- MOV AX, OLD_DOS_BUFFER_START
- MOV DOS_BUFFER_START, AX ; restore old
- MOV KB_HEAD, AX ; buffer addresses
- MOV KB_TAIL, AX ; note:
- MOV AX, OLD_DOS_BUFFER_END ; buffer is flushed
- MOV DOS_BUFFER_END, AX
- STI
- ASSUME DS: NOTHING
-
- MOV KB_INST, OFF
- LEA SI, MSG_KB_UN ; buffer-gone message
- JMPS UB_LX
-
- UB_L1:
- LEA SI, MSG_KB_NOT_PR ; error message
-
- UB_LX:
- CALL PRINT ; display message
-
- POP DS
- RET
- UNINSTALL_BUF ENDP
-
-
- INSTALL_ED PROC NEAR
-
- ;**********************************************************
- ;* Redirect interrupt 21H function 0AH to enable enhanced
- ;* editing and buffering
- ;**********************************************************
-
- PUSH ES
- CMP EDT_INST, ON ;
- JE IE_L2 ; editor already installed
-
- CMP EDT_INST, NOT_INST ; test for first turn on
- MOV EDT_INST, ON ; presence-flag on
- JNE IE_L1 ; install INT21H interrupt
- ; address, if not already done
- CLR AX ; segment 0 for interrupt-
- MOV ES, AX ; address manipulation
- LES BX, ES: [DOS_FUNCTION_INT]
- ; save old address
- MOV WORD PTR OLD_FUNCTION_INT, BX
- MOV WORD PTR OLD_FUNCTION_INT[2], ES
- MOV ES, AX
- ; replace with new address
- CLI
- MOV ES: [DOS_FUNCTION_INT], OFFSET FUNCTION_INT_ENTRY
- MOV ES: [DOS_FUNCTION_INT + 2], CS
- STI
-
- IE_L1:
- LEA SI, MSG_EDT_IN ; reinitialize message
- CALL PRINT
- LEA SI, MSG_EDT_1 ; editor specification
- CALL PRINT
- MOV AX, STR_BUF_SIZE
- CALL PRINT_NUM
- LEA SI, MSG_EDT_2
- CALL PRINT
- MOV AX, C_TBL_SIZE
- SHR AX, 1 ; size in bytes --> no-of-entries
- DEC AX ; table-size = entries - 1
- CALL PRINT_NUM
- LEA SI, MSG_EDT_3
- JMPS IE_LX
-
- IE_L2:
- LEA SI, MSG_EDT_PR ; already present message
-
- IE_LX:
- CALL PRINT ;
-
- POP ES
- RET
- INSTALL_ED ENDP
-
- UNINSTALL_ED PROC NEAR
-
- ;*****************************************************
- ;* restore INT 21H interrupt address
- ;* if not possible, zero flag is OFF at exit
- ;*****************************************************
-
- PUSH ES
-
- CMP EDT_INST, ON
- JNE UE_L2
- MOV EDT_INST, OFF
-
- CLR AX
- MOV ES, AX
-
- ;----- check whether our address still in vector
- ;
-
- CMP ES: [DOS_FUNCTION_INT], OFFSET FUNCTION_INT_ENTRY
- JNE UE_L1
- MOV AX, CS
- CMP ES: [DOS_FUNCTION_INT + 2], AX
- JNE UE_L1
-
- ;----- OK, undo revectoring
- ;
-
- MOV AX, WORD PTR OLD_FUNCTION_INT
- MOV ES: [DOS_FUNCTION_INT], AX
- MOV AX, WORD PTR OLD_FUNCTION_INT[2]
- MOV ES: [DOS_FUNCTION_INT + 2], AX
-
- MOV EDT_INST, NOT_INST
-
- UE_L1:
- LEA SI, MSG_EDT_UN ; editor-gone message
- JMPS UE_LX
- UE_L2:
- LEA SI, MSG_EDT_NOT_PR
- UE_LX:
- CALL PRINT ; editor-already-gone message
-
- POP ES
- RET
- UNINSTALL_ED ENDP
-
- RESET_EDT PROC NEAR
- MOV AX, C_TBL_START
- MOV C_TBL_HEAD, AX
- MOV C_TBL_TAIL, AX
- MOV CURRENT, AX
- RET
- RESET_EDT ENDP
-
- INSTALL_ANSI PROC NEAR
- MOV ANSI, ON
- MOV MAX_COL, 80
- RET
- INSTALL_ANSI ENDP
-
- UNINSTALL_ANSI PROC NEAR
- MOV ANSI, OFF
- RET
- UNINSTALL_ANSI ENDP
-
- RECALL PROC NEAR
-
- ;----- display all strings in STR_BUF
- ;
-
- CLR DX ; initialize
- MOV DI, C_TBL_SIZE ; DX = sequence number
- SHR DI, 1 ; DI = maximum number of strings
- DEC DI ;
- MOV BX, C_TBL_TAIL ; BX = pointer into C_TBL entry
- MOV SI, CS:[BX] ; of string currently displayed
- MOV BX, C_TBL_HEAD ;
-
- REC_L1:
- CMP BX, C_TBL_TAIL ;
- JE REC_LX ; all strings done, normal exit
-
- MOV AL, CR
- CALL WRITE_CHAR
- MOV AL, LF
- CALL WRITE_CHAR
-
- INC DX
- CMP DX, DI ; savety check, prevent endless looping
- JA RESET_EDT ; this jump should not occur, error exit
-
- MOV AX, DX
- CALL PRINT_NUM
-
- MOV AL, '.'
- CALL WRITE_CHAR
- MOV AL, ' '
- CALL WRITE_CHAR
-
- MOV CX, CS:[BX] ; last character of string
- SUB CX, SI ; compute length
- JAE REC_L2
- ADD CX, STR_BUF_SIZE
-
- REC_L2:
- INC SI ; next character
- CMP SI, STR_BUF_END
- JNE REC_L3 ; wrap around if necessary
- MOV SI, STR_BUF_START
-
- REC_L3:
- MOV AL, CS:[SI]
- CALL DISPLAY_COMPLEX
- LOOP REC_L2
-
- CALL SCROLLDO_TBL
- JMP REC_L1
-
- REC_LX:
- RET
- RECALL ENDP
-
-
-
- D_OUTPUT:
- D_OUTPUT_VER:
-
- ;************************************************************
- ;* Output routine.
- ;* Characters output to this device are interpreted as
- ;* control codes to switch the editor and buffer on and off.
- ;* Such control codes consist always of two characters:
- ;* "IK" = Install Keyboard Buffer.
- ;* "IE" = Install Keyboard Editor.
- ;* "UK" = Uninstall Keyboard Buffer.
- ;* "UE" = Uninstall Keyboard Editor.
- ;* "RE" = Reset Editor
- ;* "IA" = ANSI mode On
- ;* "UA" = ANSI mode Off
- ;*
- ;* On entry: ES:BX contains long pointer to Request Header
- ;************************************************************
-
- PUSH ES
- PUSH BX
- MOV CX, ES: [BX].COUNT ; number of characters in CX
- OR CX, CX ;
- JZ O_LX ; check for a mistake
- LES BX, ES: [BX].BUFFER_ADR ; load address of buffer
- MOV AL, ES: [BX] ; get first character from buffer
- CMP EXPECTSECOND, ON; second part expected?
- JE O_L1 ; yes: treat second part
- MOV FIRSTPART, AL ; no: save this first part
- MOV EXPECTSECOND, ON; now we do expect the second part
- CMP CX, 1 ; was there more then one?
- JBE O_LX ; no: wait for next arrival
- MOV AL, ES: [BX+1] ; yes: get second character
-
- ;----- at this point there is a complete command
- ; and we are ready for interpreting
- ;
-
- O_L1:
- MOV EXPECTSECOND, OFF
- MOV AH, FIRSTPART ; AX now contains the
- ; two letter code
- AND AX, 0DFDFH ; capitalize
- CMP AX, 'IK' ;
- JNE O_L2
- CALL INSTALL_BUF ; code = 'IK'
- JMPS O_LX
- O_L2:
- CMP AX, 'IE' ;
- JNE O_L3
- CALL INSTALL_ED ; code = 'IE'
- JMPS O_LX
- O_L3:
- CMP AX, 'UK' ;
- JNE O_L4
- CALL UNINSTALL_BUF ; code = 'UK'
- JMPS O_LX
- O_L4:
- CMP AX, 'UE' ;
- JNE O_L6
- CALL UNINSTALL_ED ; code = 'UE'
- JMPS O_LX
- O_L6:
- CMP AX, 'IA' ;
- JNE O_L7
- CALL INSTALL_ANSI ; code = 'IA'
- JMPS O_LX
- O_L7:
- CMP AX, 'UA' ;
- JNE O_L8
- CALL UNINSTALL_ANSI ; code = 'UA'
- JMPS O_LX
- O_L8:
- CMP AX, 'RC' ;
- JNE O_L9
- CALL RECALL ; code = 'UA'
- JMPS O_LX
- O_L9:
- CMP AX, 'RE'
- JNE O_LX
- CALL RESET_EDT ; code = 'RE'
-
- ;----- otherwise invalid combination
- ;
-
- O_LX:
- POP BX
- POP ES
- JMP D_EXIT ; to exit protocol
-
- ;----- round origin to paragraph boundary
- ;
-
- ORG ($ - START_CODE + 15) AND 0FFF0H
-
- END_CODE = $
-
-
- ACTIVATE DB OFF ; activate immediate switch
- P_CHAR_COUNT DW ? ; character count on parameter line
-
- MSG_INVA_SW_1 DB ' Invalid switch at position : ', NULL
- MSG_INVA_SW_2 DB ' in Configuration file'
- DB CR, LF, LF, NULL
-
- MSG_INVA_CHR_1 DB ' Invalid character at position : ', NULL
- MSG_INVA_CHR_2 DB ' in Configuration file'
- DB CR, LF, LF, NULL
-
- MSG_ADR_OVL DB ' Buffer sizes too large, reduce parameter values'
- DB ' in Configuration file'
- DB CR, LF
- DB ' Default values substituted'
- DB CR, LF, LF, NULL
-
- MSG_OVL_1 DB ' Parameter value overflow at position: ', NULL
- MSG_OVL_2 DB ' in Configuration file'
- DB CR, LF, NULL
-
- MSG_ADJUST_1 DB ' Specified size for keyboard buffer too large,'
- DB ' size adjusted to : ', NULL
- MSG_ADJUST_2 DB ' bytes', CR, LF, NULL
-
-
- GET_PARMS PROC NEAR
-
- ;*************************************************************
- ; This procedure scans the string addressed by DS:SI for
- ; the presence of parameters to the driver.
- ;
- ; Parameters must have the following format:
- ;
- ; DEVICE=\path\drv_name K:nnn B:nnn C:nnn [/A] [/N]
- ;
- ; where nnn is a decimal number.
- ;
- ; K:nnn nnn is keyboard buffer size
- ; B:nnn nnn is buffer size for command strings
- ; C:nnn nnn is maximum number of commands that can be stored
- ; /A if present: activation on driver installation
- ; /N if present: cursor control through ANSI-codes
- ;
- ;
- ; The code should implement the following:
- ;
- ; ----------------------
- ;
- ; C: CHAR;
- ; Separators = [NULL, ' ', ',', '=', ';', '+', TAB];
- ;
- ; ON EndOfLine: EXIT;
- ; REPEAT GetChar(C) UNTIL C IN Separators;
- ; REPEAT
- ; WHILE (C IN Separators) DO GetChar(C);
- ; CASE C OF
- ; 'K': OUT1 := GetNum;
- ; 'B': OUT2 := GetNum;
- ; 'C': OUT3 := GetNum;
- ; '/': [GetChar(C); IF C='A' THEN ACTIVATE := ON
- ; ELSE IF C='N' THEN ANSI := ON
- ; ];
- ;
- ; UNTIL EndOfLine;
- ;
- ; GetNum:
- ; GetNum := 0;
- ; IF C = ':' THEN GetChar(C);
- ; WHILE (C IN ['0'..'9']) DO [
- ; GetNum := GetNum*10 + (Ord(C) - Ord('0'));
- ; GetChar(C)
- ; ];
- ;
- ; ---------------------
- ;
- ;
-
- LDS SI, ES: [BX].PARMS
- MOV P_CHAR_COUNT, 7 ; assume 'DEVICE=' occupies
- ; first 7 positions in CONFIG
- GP_L1:
- CALL GET_P_CHAR
- JZ GP_LX
-
- CALL IN_SEPARATORS
- JNZ GP_L1
-
- GP_NEXT:
- CALL GET_P_CHAR
- JZ GP_LX
-
- CALL IN_SEPARATORS
- JZ GP_NEXT
-
- CMP AL, 'K'
- JNE GP_LB
-
- ;----- collect keyboard buffer size
- ;
-
- CALL GET_NUM
- OR CX, CX ; check result
- JZ GP_LK1 ; zero ?
- JS GP_LO ; > 32K ?
- SHL CX, 1 ; each keystroke fills two bytes
- MOV KBBUFFER_SIZE, CX ; in buffer
- GP_LK1:
- JMP GP_NEXT
-
- GP_LB:
- CMP AL, 'B'
- JNE GP_LC
-
- ;----- collect string buffer size
- ;
-
- CALL GET_NUM
- OR CX, CX ; check result
- JZ GP_LB1
- MOV STR_BUF_SIZE, CX
- GP_LB1:
- JMP GP_NEXT
-
- GP_LC:
- CMP AL, 'C'
- JNE GP_LS
-
- ;----- collect maximum number of commands
- ;
-
- CALL GET_NUM
- OR CX, CX ; check result
- JZ GP_LC1
- INC CX ; table-size = no-of-entries + 1
- JS GP_LO ; > 32K ?
- SHL CX, 1 ; CX = no-of-entries, convert to bytes
- MOV C_TBL_SIZE, CX
- GP_LC1:
- JMP GP_NEXT
-
- GP_LX:
- RET
-
- GP_LS:
- CMP AL, '/'
- JNE GP_L6
-
- ;----- collect switches
- ;
-
- CALL GET_P_CHAR
- JZ GP_LX
- CMP AL, 'A'
- JNE GP_LS1
- MOV ACTIVATE, ON
- JMP GP_NEXT
- GP_LS1:
- CMP AL, 'N'
- JNE GP_LS2
- MOV ANSI, ON
- JMP GP_NEXT
-
- GP_LS2:
-
- ;----- invalid switch
- ;
-
- PUSH SI
- LEA SI, MSG_INVA_SW_1
- CALL PRINT
- MOV AX, P_CHAR_COUNT
- CALL PRINT_NUM
- LEA SI, MSG_INVA_SW_2
- CALL PRINT
- POP SI
- JMP GP_L1
-
- GP_LO:
-
- ;----- overflow
- ;
-
- PUSH SI
- LEA SI, MSG_OVL_1
- CALL PRINT
- MOV AX, P_CHAR_COUNT
- DEC AX
- CALL PRINT_NUM
- LEA SI, MSG_OVL_2
- CALL PRINT
- POP SI
- JMP GP_NEXT
-
- GP_L6:
-
- ;----- invalid character on line
- ;
-
- PUSH SI
- LEA SI, MSG_INVA_CHR_1
- CALL PRINT
- MOV AX, P_CHAR_COUNT
- CALL PRINT_NUM
- LEA SI, MSG_INVA_CHR_2
- CALL PRINT
- POP SI
- JMP GP_L1 ; go on after next separator
-
-
- IN_SEPARATORS PROC NEAR
-
- ;----- determine if character is in the separator set
- ; in: AL: character
- ; return: zero flag set if Al in separators
- ; !! CR and LF are also return zero
- ;
- CMP AL, NULL
- JE IS_LX
- CMP AL, ' '
- JE IS_LX
- CMP AL, ','
- JE IS_LX
- CMP AL, '='
- JE IS_LX
- CMP AL, '+'
- JE IS_LX
- CMP AL, ';'
- JE IS_LX
- CMP AL, TAB
- JE IS_LX
- CMP AL, CR
- JE IS_LX
- CMP AL, LF
- IS_LX:
- RET
- IN_SEPARATORS ENDP
-
- GET_P_CHAR PROC NEAR
-
- ;----- return next character from parameter-string in AL
- ; if EndOfLine reached then zero-flag is set
- ;
- CMP AL, CR
- JE GPC_LX
- LODSB
- INC P_CHAR_COUNT
- CMP AL, CR
- JE GPC_LX
- CMP AL, LF
- GPC_LX:
- RET
- GET_P_CHAR ENDP
-
- PUT_P_CHAR PROC NEAR
-
- ;----- reverse last action of GET_P_CHAR
- ; AL is pushed back onto the "input-stream"
- ;
- DEC SI
- DEC P_CHAR_COUNT
- RET
- PUT_P_CHAR ENDP
-
- GET_NUM PROC NEAR
-
- ;----- read a decimal number from parameter string
- ; out: CX contains the number
- ; this routine reads only digits, when an other
- ; character is read it is pushed back through
- ; PUT_P_CHAR and the routine exits
- ;
-
- CLR CX
- CALL GET_P_CHAR
- JZ GN_LX
- CMP AL, ':'
- JNE GN_L2
- GN_L1:
- CALL GET_P_CHAR
- JZ GN_LX
- GN_L2:
- CMP AL, '9' ; test for digit
- JA GN_LX
- CMP AL, '0'
- JB GN_LX
- SUB AL, '0'
- XCHG CX, AX ; multiplication operand in AX
- MUL TEN ; x 10
- XCHG CX, AX
- JNC GN_L3 ; test for overflow
- CLR CX ; if so, return zero
- JMPS GN_LX1
- GN_L3:
- CLR AH ;
- ADD CX, AX ; add next digit
- JMP GN_L1
-
- GN_LX:
- CALL PUT_P_CHAR
- GN_LX1:
- RET
- GET_NUM ENDP
-
- GET_PARMS ENDP
-
-
- D_INIT PROC NEAR
-
- ;************************************************************
- ;* Driver initialization routine.
- ;*
- ;* !! version 2.0 only installs driver at boot-time
- ;* !! NO immediate activation of buffers and editor
- ;************************************************************
-
- PUSH ES
- PUSH BX
- MOV BIOS_TTY_SW, ON
-
- MOV AX, CS
- MOV DS, AX ; tell about the instal-
- LEA SI, MSG_VERSION ; lation of this driver
- CALL PRINT ;
-
- CALL GET_PARMS
-
- ;----- check the parameters
- ;
-
- MOV CL, 4
- MOV AX, KBBUFFER_SIZE ; compute end of KBBUFFER
- ADD AX, 0FH ;
- SHR AX, CL ; paragraph format
- ADD AX, (END_CODE - START_CODE) SHR 4
- MOV CX, CS ; add segment paragraph number
- ADD AX, CX ;
- SUB AX, 1000H ; must not exceed first 64K
- JBE D_IN_L2
- MOV CL, 4 ;
- SHL AX, CL ; in bytes again
- SUB KBBUFFER_SIZE, AX ; adjust KBBUFFER_SIZE
- JNC D_IN_L1 ; no negative values
- MOV KBBUFFER_SIZE, 0
-
- D_IN_L1:
- LEA SI, MSG_ADJUST_1 ;
- CALL PRINT ; display message
- MOV AX, KBBUFFER_SIZE ; and new size of KBBUFFER
- CALL PRINT_NUM ;
- LEA SI, MSG_ADJUST_2 ;
- CALL PRINT
-
- D_IN_L2:
- LEA AX, END_CODE
- MOV KBBUFFER, AX ; set start address of KB-buffer
-
- ADD AX, KBBUFFER_SIZE
- MOV STR_BUF_START, AX ; initialize command string
- MOV STR_BUF_HEAD, AX ; buffer data-structure
- MOV STR_BUF_TAIL, AX ;
- ADD AX, STR_BUF_SIZE ;
- JC D_IN_ERR ; test for overflow
-
- MOV STR_BUF_END, AX ;
-
- MOV SI, AX ; initialize first entry
- MOV CS:[SI], AX ; in C_TBL with address of
- DEC WORD PTR CS:[SI] ; last byte in STR_BUF
-
- MOV C_TBL_START, AX ; start address of C_TBL
- MOV C_TBL_HEAD, AX ;
- MOV C_TBL_TAIL, AX ;
- MOV CURRENT, AX
- ADD AX, C_TBL_SIZE ; now AX = end of resident code
- JC D_IN_ERR ; test for overflow
- MOV C_TBL_END, AX ; end of C_TBL
-
- ;----- fill in in Request Header
- ;
-
- MOV WORD PTR ES: [BX].END_ADR, AX
- MOV WORD PTR ES: [BX].END_ADR+2, CS
-
- CMP ACTIVATE, ON ; /A switch present ?
- JNE D_IN_LX
- CALL INSTALL_BUF ; if so, install now
- CALL INSTALL_ED ;
-
- D_IN_LX:
- MOV BIOS_TTY_SW, OFF ; display through DOS
- POP BX
- POP ES
- JMP D_EXIT ; initialization done:
- ; to exit protocol
- D_IN_ERR:
- LEA SI, MSG_ADR_OVL ; address-overflow message
- CALL PRINT ;
- MOV C_TBL_SIZE, 32 ; set default values
- MOV STR_BUF_SIZE, 512 ; these values should not
- MOV ACTIVATE, OFF ; cause trouble
- JMP D_IN_L2 ; try again
-
- D_INIT ENDP
-
- CODE ENDS
- END
-
-